package websocket

import (
	"context"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/text/gstr"
	"websocket/internal/consts"
	"websocket/utility"
)

type wLogicManager struct {
	functions map[string]map[string]func(ctx context.Context, work *consts.WebsocketWorkContext) (*consts.WebsocketWorkRes, error) //define operation func
}

var (
	insLogicManager = wLogicManager{
		functions: map[string]map[string]func(ctx context.Context, work *consts.WebsocketWorkContext) (*consts.WebsocketWorkRes, error){
			"sys": {
				"ping":  SysFunc().Ping,
				"pong":  SysFunc().Pong,
				"panic": SysFunc().Panic,
			},
			"message": {
				"point": MessageFunc().Point,
			},
		},
	}
)

func LogicManager() *wLogicManager {
	return &insLogicManager
}

//Call 命令解析调用方法
func (l *wLogicManager) Call(ctx context.Context, work *consts.WebsocketWorkContext) (callBack []*consts.WebsocketWorkRes) {
	g.TryCatch(ctx, func(ctx context.Context) {
		callBack = []*consts.WebsocketWorkRes{}
		if gstr.Contains(work.Cmd, ".") {
			//指定调用(支持批量)
			commands := gstr.Explode(".", work.Cmd)
			//循环上行指令组 commands[0]为组名称 commands[1:]为组下指令名称
			for _, command := range commands[1:] {
				if command == "" {
					callBack = Manager().BuildRes(ctx, &consts.WebsocketWorkRes{
						Code:   consts.WebsocketStatusUndefinedFunc,
						Msg:    "undefined",
						Unique: work.Unique,
						Data:   nil,
					})
					continue
				}
				back, _ := l.callFunc(ctx, commands[0], command, work)
				callBack = Manager().BuildRes(ctx, back, callBack...)
				//callBack = append(callBack, back)
			}
		} else {
			//整组调用
			callBack = l.callAllFunc(ctx, work.Cmd, work)
		}
	}, l.runRecover)
	return
}

//callAllFunc 调用组命令
func (l *wLogicManager) callAllFunc(ctx context.Context, group string, work *consts.WebsocketWorkContext) (back []*consts.WebsocketWorkRes) {
	_ = g.Try(ctx, func(ctx context.Context) {
		back = []*consts.WebsocketWorkRes{}
		functions, ok := l.functions[group]
		if !ok {
			back = Manager().BuildRes(ctx, &consts.WebsocketWorkRes{
				Code:   consts.WebsocketStatusUndefinedFunc,
				Msg:    "undefined",
				Unique: work.Unique,
				Data:   nil,
			})
		}
		for method := range functions {
			call, _ := l.callFunc(ctx, group, method, work)
			back = Manager().BuildRes(ctx, call, back...)
		}
	})
	return
}

//callFunc 调用指定方法
func (l *wLogicManager) callFunc(ctx context.Context, group, alias string, work *consts.WebsocketWorkContext) (data *consts.WebsocketWorkRes, err error) {
	g.TryCatch(ctx, func(ctx context.Context) {
		f, ok := l.functions[group][alias]
		if !ok {
			err = utility.Common.BuildErr(ctx, consts.WebsocketStatusUndefinedFunc, "undefined")
			return
		}
		data, err = f(ctx, work)
		return
	}, func(ctx context.Context, exception error) {
		data = &consts.WebsocketWorkRes{
			Code:   consts.WebsocketStatusPanicErr,
			Msg:    "server err[" + exception.Error() + "]",
			Unique: work.Unique,
			Data:   nil,
		}
		err = exception
		l.runRecover(ctx, exception)
	})
	return
}

func (l *wLogicManager) runRecover(ctx context.Context, err error) {
	g.Log().Cat("logic").Info(ctx, Context().GetLogger(ctx), gerror.Stack(err))
}
